package org.iabako.server.dao.user;

import org.iabako.server.dao.JpaDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.business.NotificationConfig;
import org.iabako.shared.entity.user.Enterprise;
import org.iabako.shared.entity.user.EnterpriseCustomInfo;
import org.iabako.shared.entity.user.User;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 18/02/15.
 */

@Repository("enterpriseDAO")
public class EnterpriseDAO extends JpaDAO<Long, Enterprise> {

    @Override
    protected String getUniqueNumberVerificationQuery() {
        return null;
    }

    @Override
    protected String getLastNumberQuery() {
        return null;
    }

    public List<EnterpriseCustomInfo> getCustomInfoList() {
        Enterprise enterprise = getSessionUser().getEnterprise();
        enterprise = enterprise.getParentEnterprise() == null ? enterprise : enterprise.getParentEnterprise();
        String query = "SELECT e.customInfoList FROM Enterprise e WHERE e = :enterprise";
        return entityManager.createQuery(query).setParameter("enterprise", enterprise).getResultList();
    }

    public void mergeCustomList(Enterprise enterprise, List<EnterpriseCustomInfo> customInfoList) {
        Enterprise enterpriseFromDB = findById(enterprise.getId());

        for (EnterpriseCustomInfo customInfoInDB : enterpriseFromDB.getCustomInfoList()) {
            if (!customInfoList.contains(customInfoInDB)) {
                entityManager.remove(customInfoInDB);
            }
        }

        for (EnterpriseCustomInfo customInfo : customInfoList) {
            customInfo.setEnterprise(enterpriseFromDB);
            entityManager.merge(customInfo);
        }
    }

    public NotificationConfig saveNotificationConfig(NotificationConfig entity) {
        return entityManager.merge(entity);
    }

    public List<Enterprise> getEnterpriseWithoutNotificationEmail() {
        String query = "SELECT e FROM Enterprise e JOIN e.users " +
                "WHERE e.demo <> 1 " +
                "AND (SELECT count(u) FROM User u JOIN u.userCredit credit WHERE u.enterprise = e " +
                "AND credit.expirationDate >= :today " +
                "AND (u.lastNotificationEmail IS NULL OR u.lastNotificationEmail < :today)) > 0";
        return entityManager.createQuery(query).setParameter("today", new ServerTools().resetTime(new Date())).getResultList();
    }

    public List<Enterprise> getChildrenEnterprises(Enterprise enterprise) {
        String query = "SELECT e FROM Enterprise e WHERE e.parentEnterprise = :enterprise";
        return entityManager.createQuery(query).setParameter("enterprise", enterprise).getResultList();
    }

    public List<Enterprise> getAllRelatedEnterprises(Enterprise enterprise) {
        List<Enterprise> enterprises = new ArrayList<Enterprise>();
        if (enterprise.getParentEnterprise() == null) {
            //May be it's a parent Enterprise
            enterprises.add(enterprise);
            enterprises.addAll(enterprise.getChildrenEnterprises());
        } else {
            //it's a child Enterprise
            enterprises = getChildrenEnterprises(enterprise.getParentEnterprise());
            enterprises.add(enterprise.getParentEnterprise());
        }
        return enterprises;
    }

    public int getUsersNumber(Enterprise enterprise) {
        int usersNumber = 0;
        for (Enterprise e : enterprise.getAllRelatedEnterprises()) {
            String query = "SELECT COUNT (u) FROM User u WHERE u.enterprise = :e";
            usersNumber += (Long) entityManager.createQuery(query).setParameter("e", e).getSingleResult();
        }
        return usersNumber;
    }

    public void detachLimitedVisibilityEnterprises(Long id) {
        //We attach all information to it's parentEnterprise before detach parent-child relationship
        //TODO delete orphan enterprises

        String query = "UPDATE Client c SET c.enterprise = (SELECT e.parentEnterprise FROM Enterprise e WHERE e.id = :id) WHERE c.enterprise.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Service s SET s.enterprise = (SELECT e.parentEnterprise FROM Enterprise e WHERE e.id = :id) WHERE s.enterprise.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Product p SET p.enterprise = (SELECT e.parentEnterprise FROM Enterprise e WHERE e.id = :id) WHERE p.enterprise.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Sale s SET s.enterprise = (SELECT e.parentEnterprise FROM Enterprise e WHERE e.id = :id) WHERE s.enterprise.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Expense e SET e.enterprise = (SELECT e.parentEnterprise FROM Enterprise e WHERE e.id = :id) WHERE e.enterprise.id = :id";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();

        query = "UPDATE Enterprise e SET e.parentEnterprise = NULL where e = (SELECT u.enterprise FROM User u WHERE u.id = :id)";
        entityManager.createQuery(query).setParameter("id", id).executeUpdate();
    }

    public Enterprise getDemoEnterprise() {
        String query = "select e from Enterprise e where e.demo = 1";
        List<Enterprise> demoEnterprises = entityManager.createQuery(query).getResultList();
        return demoEnterprises != null && demoEnterprises.size() > 0 ? demoEnterprises.get(0) : null;
    }

    public List<Enterprise> getEnterprisesCreatedOn(Date date) {
        ServerTools serverTools = new ServerTools();
        date = serverTools.resetTime((Date) date.clone());
        Date datePlusOne = serverTools.addDaysToDate((Date) date.clone(), 1);

        String query = "SELECT e FROM Enterprise e " +
                "WHERE e.creationDate >= :date AND e.creationDate <= :datePlusOne";

        return entityManager.createQuery(query).setParameter("date", date).setParameter("datePlusOne", datePlusOne).getResultList();
    }

    public List<Enterprise> getActiveEnterprises() {
        String query = "SELECT DISTINCT e FROM Enterprise e JOIN e.users u JOIN u.userCredit credit " +
                "WHERE credit.expirationDate >= :today";
        return entityManager.createQuery(query).setParameter("today", new ServerTools().resetTime(new Date())).getResultList();
    }

    public User getPrincipalUser(Enterprise e) {
        String query = "SELECT u FROM User u where u.principal = 1 AND u.enterprise = :enterprise";
        Enterprise enterprise = e.isChild() ? e.getParentEnterprise() : e;
        return (User) entityManager.createQuery(query).setParameter("enterprise", enterprise).getSingleResult();
    }
}
